﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.ComponentModel.Composition;

using NuMetaheuristics;
using NuMetaheuristics.Genotypes;
using NuMetaheuristics.Utility;

namespace NuMetaheuristics.Operators.Vector
{
    /// <summary>
    /// Modify each element of a vector with the given value modifier.
    /// </summary>
    [DataContract(Namespace = "http://numetaheuristics.codeplex.com/schemas")]
    [Export(typeof(IUnaryOperator<DoubleVectorGenotype>))]
    public class DoubleVectorMutator : IUnaryOperator<DoubleVectorGenotype>, IDeserializationCallback
    {
        [DataMember]
        private IUnaryOperator<double> _valueMutator;
        private RandomNumberGenerator _rng;
        
        public DoubleVectorMutator()
        {
            _rng = new RandomNumberGenerator();
        }

        public DoubleVectorMutator(IUnaryOperator<double> valueMutator)
        {
            _rng = new RandomNumberGenerator();
            _valueMutator = valueMutator;
        }

        public void OnDeserialization(object sender)
        {
            _rng = new RandomNumberGenerator();
        }

        public virtual void Operate(ref DoubleVectorGenotype operand)
        {
            if (_valueMutator == null)
                throw new NullReferenceException();

            if (operand == null)
                throw new ArgumentNullException();

            for (int i = 0; i < operand.Vector.Length; i++)
            {
                if(_rng.Next(0,2) == 0)
                {
                    _valueMutator.Operate(ref operand.Vector[i]);
                }
            }
        }
    }

    /// <summary>
    /// Modify each element of a vector with the given value modifier.
    /// </summary>
    [DataContract(Namespace = "http://numetaheuristics.codeplex.com/schemas")]
    [Export(typeof(IUnaryOperator<IntegerVectorGenotype>))]
    public class IntegerVectorMutator : IUnaryOperator<IntegerVectorGenotype>, IDeserializationCallback
    {
        [DataMember]
        private IUnaryOperator<int> _valueMutator;
        private RandomNumberGenerator _rng;
        
        public IntegerVectorMutator()
        {
            _rng = new RandomNumberGenerator();
        }

        public IntegerVectorMutator(IUnaryOperator<int> valueMutator)
        {
            _rng = new RandomNumberGenerator();
            _valueMutator = valueMutator;
        }

        public void OnDeserialization(object sender)
        {
            _rng = new RandomNumberGenerator();
        }

        public virtual void Operate(ref IntegerVectorGenotype operand)
        {
            if (_valueMutator == null)
                throw new NullReferenceException();

            if (operand == null)
                throw new ArgumentNullException();

            for (int i = 0; i < operand.Vector.Length; i++)
            {
                if (_rng.Next(0, 2) == 0)
                {
                    _valueMutator.Operate(ref operand.Vector[i]);
                }
            }
        }
    }

    /// <summary>
    /// Modify each element of a vector with the given value modifier.
    /// </summary>
    [DataContract(Namespace = "http://numetaheuristics.codeplex.com/schemas")]
    [Export(typeof(IUnaryOperator<BooleanVectorGenotype>))]
    public class BooleanVectorMutator : IUnaryOperator<BooleanVectorGenotype>, IDeserializationCallback
    {
        [DataMember]
        private IUnaryOperator<bool> _valueMutator;
        private RandomNumberGenerator _rng;

        public BooleanVectorMutator()
        {
            _rng = new RandomNumberGenerator();
        }

        public BooleanVectorMutator(IUnaryOperator<bool> valueMutator)
        {
            _rng = new RandomNumberGenerator();
            _valueMutator = valueMutator;
        }

        public void OnDeserialization(object sender)
        {
            _rng = new RandomNumberGenerator();
        }

        public virtual void Operate(ref BooleanVectorGenotype operand)
        {
            if (_valueMutator == null)
                throw new NullReferenceException();

            if (operand == null)
                throw new ArgumentNullException();

            for (int i = 0; i < operand.Vector.Length; i++)
            {
                if (_rng.Next(0, 2) == 0)
                {
                    _valueMutator.Operate(ref operand.Vector[i]);
                }
            }
        }
    }

}
